// 接受请求，分发中转到模块
// @version go-utils 0.1
// @author xiaotangren  <unphp@qq.com>
// @data 2014-07-21
package socket

import (
	"encoding/json"
	"fmt"
	"net"
	"strconv"
	"time"

	"git.oschina.net/unphp/go-utils/base"
)

//接受请求的数据结构
type SocketParamsJson struct {
	Module     string
	Controller string
	Action     string
	Data       interface{}
}

type ConnSocket struct {
	Conn net.Conn
	Data map[string]interface{}
}

//接受请求，分发处理
func (this *ConnSocket) Doing() {
	defer func() {
		this.Conn.Close()
		if err := recover(); err != nil {
			log(fmt.Sprint(err))
			rsData := base.SendData{}
			rsData.Code = 0
			rsData.Error = fmt.Sprint(err)
			rsData1, _ := json.Marshal(rsData)
			rs := string(rsData1)
			this.ConnWrite(rs)
			return
		}
	}()
	this.Conn.SetDeadline(time.Now().Add(10 * time.Second)) //设置超时时间（对读、写都起作用，超过时间，自动关闭）
	headerinfo := make([]byte, 10)                          //“请求头信息”大小
	datainfo := make([]byte, 0)                             //每次read的缓冲大小
	var readLen int                                         //需要读取的数据大小
	var readBufferLen int = 1024                            //每次读取的分片单元大小
	newRequest := true                                      //是否是一次新的请求
	for {
		if newRequest {
			//----------------------------------
			//读取“请求头信息”，
			//大小为10个字节，
			//包含着“本次请求”总共将接受到多少个字节。
			//----------------------------------
			get := ""
			_, err := this.Conn.Read(headerinfo)
			if err != nil {
				break
			}
			for _, b := range headerinfo {
				if b == 0 {
					continue
				}
				get = get + string(b)
			}
			readLen, _ = strconv.Atoi(get)
			log(get)
			fmt.Println(readLen)
			newRequest = false
		} else {
			if readLen <= 0 {
				rsData := base.SendData{}
				rsData.Code = 0
				rsData.Error = "socket request no data!"
				rsData1, _ := json.Marshal(rsData)
				rs := string(rsData1)
				this.ConnWrite(rs)
				return
			}
			//----------------------------------
			//读取“本次请求”剩下的数据---
			//“请求头信息”之后的所有数据。
			//当数据超过1024（上面设置的“分片单元”）
			//时，将分片读取。
			//----------------------------------
			readTimes := 0              //读取的次数
			readTimesMaxLimit := 10000  //读取次数的限制（主要是为了保护，防止死循环的出现）
			readData := make([]byte, 0) //读取到是数据（累加的）
			for readTimes < readTimesMaxLimit {
				readTimes++
				lastLen := readLen - readBufferLen
				if lastLen <= 0 {
					//----------------------------------
					//当剩下的数据字节长度小于1024，
					//则读完后返回结果。。。。
					//----------------------------------
					datainfo = make([]byte, readLen)
					n, err := this.Conn.Read(datainfo)
					if err != nil {
						break
					}
					//lostLen := this.checkLost(&readData, datainfo)  //废除，以前的做法错误！
					lostLen := readLen - n                        // ++
					readData = append(readData, datainfo[0:n]...) // ++
					if lostLen > 0 {
						if readData, err = this.readLastData(readData, lostLen); err != nil {
							break
						}
					}
					this.sendsData(readData)
					newRequest = true
					break
				} else {
					//----------------------------------
					//当剩下的数据字节长度大于1024，
					//则读取1024个字节。。。。
					//----------------------------------
					datainfo = make([]byte, readBufferLen)
					n, err := this.Conn.Read(datainfo)
					if err != nil {
						break
					}
					//lostLen := this.checkLost(&readData, datainfo)  //废除，以前的做法错误！
					lostLen := readBufferLen - n                  // ++
					readData = append(readData, datainfo[0:n]...) // ++
					readLen = lastLen + lostLen
				}
			}
		}
	}
}

//递归读取剩下的丢失的数据，直至读到为止。
func (this *ConnSocket) readLastData(readData []byte, lastLen int) ([]byte, error) {
	datainfo := make([]byte, lastLen)
	n, err := this.Conn.Read(datainfo)
	if err != nil {
		return readData, err
	}
	//lostLen := this.checkLost(&readData, datainfo)  //废除，以前的做法错误！
	lostLen := lastLen - n                        // ++
	readData = append(readData, datainfo[0:n]...) // ++
	if lostLen > 0 {
		return this.readLastData(readData, lostLen)
	} else {
		return readData, nil
	}
}

//废除，以前的做法错误！
//计算本次接收过程中，其中无效的数据字节数
func (this *ConnSocket) checkLost(readData *[]byte, datainfo []byte) int {
	lostLen := 0 //无效的数据字节长度（丢失的数据）
	for _, b := range datainfo {
		if b == 0 {
			lostLen = lostLen + 1
			continue
		}
		*readData = append(*readData, b)
	}
	fmt.Println(len(*readData), lostLen)
	return lostLen
}

//处理接受到的数据，并最终返回结果。
func (this *ConnSocket) sendsData(get []byte) {
	defer func() {
		if err := recover(); err != nil {
			log(fmt.Sprint(err))
			rsData := base.SendData{}
			rsData.Code = 0
			rsData.Error = fmt.Sprint(err)
			rsData1, _ := json.Marshal(rsData)
			rs := string(rsData1)
			this.ConnWrite(rs)
			return
		}
	}()
	params := new(SocketParamsJson)
	log(strconv.Itoa(len(get)))
	err2 := json.Unmarshal(get, params)
	var rsData base.SendData
	if err2 != nil {
		//json解析失败
		rsData = base.SendData{}
		rsData.Code = 0
		rsData.Error = err2.Error()
		log(err2.Error())
	} else {
		//json解析成功
		if models, err := getModulesRoute(params.Module); err == nil {
			//交由模块进行处理
			rsData = models.Route(params.Controller, params.Action, params.Data)
		} else {
			rsData = base.SendData{}
			rsData.Code = 0
			rsData.Error = err.Error()
		}
	}
	if rsData1, err := json.Marshal(rsData); err != nil {
		log(err.Error())
		rsData = base.SendData{}
		rsData.Code = 0
		rsData.Error = err.Error()
		rsData1, _ := json.Marshal(rsData)
		rs := string(rsData1)
		this.ConnWrite(rs)
	} else {
		rs := string(rsData1)
		this.ConnWrite(rs)
	}
}

//返回结果
func (this *ConnSocket) ConnWrite(rs string) {
	first := this.FirstLeninfo(rs)
	sendbyte := []byte(rs)
	send := append(first, sendbyte...)
	fmt.Println(send)
	this.Conn.Write(send)
}

//返回的“信息头”---包含将要返回多少字节给客户端
func (this *ConnSocket) FirstLeninfo(str string) []byte {
	minsend := make([]byte, 10)
	first := append([]byte(strconv.Itoa(len(str))), minsend...)
	first = first[0:10]
	return first
}
